package com.md.util;

import com.google.common.collect.Lists;
import com.md.value.constants.DateConstants;
import com.md.value.enums.CalendarEnum;
import lombok.experimental.UtilityClass;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.TimeZone;

/**
 * 2021-11-01 20:21
 *
 * @author 刘骄阳
 */
@UtilityClass
public class DateUtils {
  private static final String[] DATE_STR =
    {"yyyy-MM-dd", "yyyy-MM-d", "yyyy-M-dd", "yyyy-M-d", "yyyyMMdd", "yyyyMMd", "yyyyMdd", "yyyyMd", "yyyy年MM月dd日",
      "yyyy年MM月d日", "yyyy年M月dd日", "yyyy年M月d日", "yyyy/MM/dd", "yyyy/MM/d", "yyyy/M/dd", "yyyy/M/d",
      "yyyy.MM.dd", "yyyy.MM.d", "yyyy.M.dd", "yyyy.M.d", "yyyy年MM月dd号"};

  private static final List<String> DATE_FORMAT = Lists.newArrayList("yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss",
    "yyyy年MM月dd日", "yyyy/MM/dd", "yyyy.MM.dd", "yyyy年MM月dd号");

  /**
   * 获取今天最小的时间
   *
   * @return 今天最小的时间
   */
  public static Date getTodayMin() {
    return Date.from(LocalDateTime.of(LocalDateTime.now().toLocalDate(),
      LocalTime.MIN).atZone(ZoneId.systemDefault()).toInstant());
  }

  /**
   * @param date 构建日期
   * @return 日期
   */
  public static Date parseDate(final String date) {
    for (String format : DATE_FORMAT) {
      try {
        return new SimpleDateFormat(format).parse(date);
      } catch (Exception e) {
        continue;
      }
    }
    return null;
  }

  /**
   * @param date 构建日期
   * @return 日期
   */
  public static LocalDateTime parseLocalDateTime(final String date) {
    Date temp = parseDate(date);
    if (temp == null) {
      return null;
    }
    return temp.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
  }

  /**
   * @param date 构建日期
   * @return 日期
   */
  public static LocalDate parseLocalDate(final String date) {
    Date temp = parseDate(date);
    if (temp == null) {
      return null;
    }
    return temp.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
  }

  /**
   * 获取今天最大的时间
   *
   * @return 今天最大的时间
   */
  public static Date getTodayMax() {
    return Date.from(LocalDateTime.of(LocalDateTime.now().toLocalDate(), LocalTime.MAX).atZone(ZoneId.systemDefault())
      .toInstant());
  }

  /**
   * 格式化日期
   *
   * @param date 日期
   * @return String类型的日期
   */
  public static String format(final Date date) {
    return format(date, "yyyy-MM-dd HH:mm:ss");
  }

  /**
   * 格式化日期
   *
   * @param date 日期
   * @return String类型的日期
   */
  public static String format(final Long date) {
    return format(new Date(date), "yyyy-MM-dd HH:mm:ss");
  }

  /**
   * 按照指定类型格式化日期
   *
   * @param date   日期
   * @param format 指定格式
   * @return String类型的日期
   */
  public static String format(final Date date, final String format) {
    return new SimpleDateFormat(format).format(date);
  }

  /**
   * 按照指定类型格式化日期
   *
   * @param date   日期
   * @param format 指定格式
   * @return String类型的日期
   */
  public static String format(final LocalDateTime date, final String format) {
    return new SimpleDateFormat(format).format(Date.from(date.atZone(ZoneId.systemDefault()).toInstant()));
  }

  /**
   * 按照指定类型格式化日期
   *
   * @param date 日期
   * @return String类型的日期
   */
  public static String format(final LocalDateTime date) {
    return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Date.from(date.atZone(ZoneId.systemDefault()).
      toInstant()));
  }

  /**
   * 将String类型序列化成LocalDateTime
   *
   * @param date 字符串类型的时间
   * @return LocalDateTime
   */
  public static LocalDateTime parseLocalDateTime(final String date, final String format) {
    return LocalDateTime.parse(date, DateTimeFormatter.ofPattern(format));
  }

  public static Date parse(final String date) {
    try {
      return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(date);
    } catch (ParseException e) {
      return null;
    }
  }

  public static LocalDateTime parse(final Long milliSecond) {
    return LocalDateTime.ofInstant(Instant.ofEpochMilli(milliSecond), ZoneId.systemDefault());
  }

  public static Date parse(final String date, final String format) {
    try {
      return new SimpleDateFormat(format).parse(date);
    } catch (ParseException e) {
      return null;
    }
  }


  /**
   * 获取指定时间之后的时间
   *
   * @param field  Calendar的静态属性
   * @param amount 指定时间(可以是负数)
   * @return 指定时间之后的时间
   */
  public static Date getSpecifiedTime(final CalendarEnum field, final int amount) {
    Calendar calendar = Calendar.getInstance();
    calendar.add(field.getCode(), amount);
    return calendar.getTime();
  }

  /**
   * 从指定日期开始,获取指定时间之后的时间
   *
   * @param date   日期
   * @param field  Calendar枚举
   * @param amount 指定时间(可以是负数)
   * @return 指定时间之后的时间
   */
  public static Date getSpecifiedTime(final Date date, final CalendarEnum field, final int amount) {
    Calendar calendar = Calendar.getInstance();
    calendar.setTime(date);
    calendar.add(field.getCode(), amount);
    return calendar.getTime();
  }

  /**
   * 获取指定时间到现在相差多久
   *
   * @param date 指定时间
   * @return 相差多久
   */
  public static String timeDifference(final Date date) {
    return timeDifference(date.getTime(), System.currentTimeMillis());
  }

  /**
   * 获取指定时间到现在相差多久
   *
   * @param date 指定时间
   * @return 相差多久
   */
  public static String timeDifference(final Long date) {
    return timeDifference(date, System.currentTimeMillis());
  }

  /**
   * 获取开始时间到结束时间相差多久
   *
   * @param startTime 开始时间
   * @param endTime   结束时间
   * @return 相差多久
   */
  public static String timeDifference(final LocalDateTime startTime, final LocalDateTime endTime) {
    return timeDifference(startTime.toInstant(ZoneOffset.of("+8")).toEpochMilli(),
      endTime.toInstant(ZoneOffset.of("+8")).toEpochMilli());
  }

  /**
   * 获取两个时间相差多久
   *
   * @param date  时间1
   * @param date2 时间2
   * @return 相差多久
   */
  public static String timeDifference(final Date date, final Date date2) {
    return timeDifference(date.getTime(), date2.getTime());
  }

  /**
   * 获取两个时间相差多久
   *
   * @param date  时间1
   * @param date2 时间2
   * @return 相差多久
   */
  public static String timeDifference(final Long date, final Long date2) {
    SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss-SSS");
    formatter.setTimeZone(TimeZone.getTimeZone("GMT+00:00"));
    //格式转换
    String[] hms;
    if (date > date2) {
      hms = formatter.format(date - date2).split("-");
    } else {
      hms = formatter.format(date2 - date).split("-");
    }
    return format(hms);
  }

  /**
   * 格式化毫秒数为小时
   *
   * @param date 时间
   * @return 格式化后的时间
   */
  public static String formatToDiff(final Long date) {
    SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss-SSS");
    formatter.setTimeZone(TimeZone.getTimeZone("GMT+00:00"));
    String[] hms = formatter.format(date).split("-");
    return format(hms);
  }

  /**
   * 格式化时间
   *
   * @param hms [年, 月, 日, 时, 分, 秒, 毫秒]
   * @return 格式化后的时间
   */
  private static String format(final String[] hms) {
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < hms.length; i++) {
      int sum = Integer.parseInt(hms[i]) - DateConstants.START_DATE[i];
      if (sum <= 0) {
        continue;
      }
      sb.append(sum).append(DateConstants.UNIT[i]);
    }
    return sb.toString();
  }

  public static Long today() {
    return LocalDateTime.now().toInstant(ZoneOffset.of("+8")).toEpochMilli();
  }

  /**
   * 校验时间是否失效
   *
   * @param startDate     开始时间
   * @param effectiveTime 有效时间(分钟)
   * @return true: 失效; false: 有效
   */
  public static boolean judgeDateIsEffectiveTime(final LocalDateTime startDate, final Long effectiveTime) {
    return startDate.plusMinutes(effectiveTime).isAfter(LocalDateTime.now());
  }

  /**
   * 时间戳 转LocalDateTime
   *
   * @return 时间
   */
  public static LocalDateTime second2dateTime(final Long dateTimeSecond) {
    return LocalDateTime.ofEpochSecond(dateTimeSecond, 0, ZoneOffset.ofHours(+8));
  }
}
